﻿#include "gif.h"
#include "qtlottiewidget.h"
#include <QDir>
#include <QFileInfo>

class GifBuilder {
public:
    explicit GifBuilder(const std::string &fileName , const uint32_t width,
        const uint32_t height, QColor color, const uint32_t delay = 2)
    {
        GifBegin(&handle, fileName.c_str(), width, height, delay);
        bgColor = color;
    }
    ~GifBuilder()
    {
        GifEnd(&handle);
    }
    void addFrame(rlottie::Surface &s, uint32_t delay = 2,
        bool useTransparentMask = false)
    {
        argbTorgba(s);
        GifWriteFrame(&handle,
            reinterpret_cast<uint8_t *>(s.buffer()),
            s.width(), s.height(), delay, 8, false, useTransparentMask);
    }
    void argbTorgba(rlottie::Surface &s)
    {
        uint8_t *buffer = reinterpret_cast<uint8_t *>(s.buffer());
        uint32_t totalBytes = s.height() * s.bytesPerLine();

        int bgColorR = bgColor.red() * bgColor.alphaF();
        int bgColorG = bgColor.green() * bgColor.alphaF();
        int bgColorB = bgColor.blue() * bgColor.alphaF();
        for (uint32_t i = 0; i < totalBytes; i += 4) {
           unsigned char a = buffer[i+3];
           // compute only if alpha is non zero
           if (a > 0) {
               unsigned char r = buffer[i+2];
               unsigned char g = buffer[i+1];
               unsigned char b = buffer[i];

               if (a != 255) { //un premultiply
                   unsigned char r2 = (unsigned char) ((float) bgColorR * ((float) (255 - a) / 255));
                   unsigned char g2 = (unsigned char) ((float) bgColorG * ((float) (255 - a) / 255));
                   unsigned char b2 = (unsigned char) ((float) bgColorB * ((float) (255 - a) / 255));
                   buffer[i] = r + r2;
                   buffer[i+1] = g + g2;
                   buffer[i+2] = b + b2;

               } else {
                 // only swizzle r and b
                 buffer[i] = r;
                 buffer[i+2] = b;
               }
           } else {
               buffer[i+2] = bgColorB;
               buffer[i+1] = bgColorG;
               buffer[i] = bgColorR;
           }
        }
    }
private:
    GifWriter handle;
    QColor bgColor;
};


bool lottie2gif(
    const QString& lottieFile, const QString& gifFile,
    const QColor& bgColor, const QSize& size,
    bool useTransparentBit)
{
    QFile jsonFile(lottieFile);
    if(!jsonFile.open(QFile::ReadOnly))
        return false;
    QByteArray data = jsonFile.readAll();
    QFileInfo info(lottieFile);
    QString resPath = info.absolutePath() + "/";
    resPath = QDir::fromNativeSeparators(resPath);
    auto player = rlottie::Animation::loadFromData(data.data(),
        info.baseName().toLocal8Bit().data(), resPath.toLocal8Bit().data());
    //auto player = rlottie::Animation::loadFromFile(lottieFile.toLocal8Bit().data());
    if (!player)
        return false;
    size_t w = 0, h = 0;
    player->size(w, h);
    if(size.width() > 0)
        w = size.width();
    if(size.height() > 0)
        h = size.height();

    QImage img(w, h, QImage::Format_ARGB32);
    size_t frameCount = player->totalFrame();

    QString exportFile = gifFile;
    QFileInfo gifInfo(gifFile);
    if(gifInfo.suffix().toLower() != "gif")
        exportFile.append(".gif");
    GifBuilder builder(exportFile.toLocal8Bit().data(), w, h, bgColor);
    for (size_t i = 0; i < frameCount ; i++) {
        rlottie::Surface surface((uint32_t*)img.bits(), w, h, (w << 2));
        player->renderSync(i, surface);
        builder.addFrame(surface, 2, useTransparentBit);
    }
    return true;
}

bool QtLottieWidget::exportGif(
    const QString& gifFile, const QColor& bgColor,
    const QSize& size, bool useTransparentBit)
{
    QMutexLocker locker(&m_mutex);
    if(!m_player)
        return false;
    size_t w = 0, h = 0;
    m_player->size(w, h);
    if(size.width() > 0)
        w = size.width();
    if(size.height() > 0)
        h = size.height();

    QImage img(w, h, QImage::Format_ARGB32);
    size_t frameCount = m_player->totalFrame();

    QString exportFile = gifFile;
    QFileInfo gifInfo(gifFile);
    if(gifInfo.suffix().toLower() != "gif")
        exportFile.append(".gif");
    GifBuilder builder(exportFile.toLocal8Bit().data(), w, h, bgColor);
    for (size_t i = 0; i < frameCount ; i++) {
        rlottie::Surface surface((uint32_t*)img.bits(), w, h, (w << 2));
        m_player->renderSync(i, surface);
        builder.addFrame(surface, 2, useTransparentBit);
    }
    return true;
}
